#include "stdafx.h"
#include "CppUnitTest.h"

#include <vex.tests/mstest/tests.core/user_contract.h>
#include <vex.tests/mstest/tests.core/user_base.h>
#include <vex.tests/mstest/tests.core/user_type_traits.h>
#include <vex.tests/mstest/tests.core/tests.core.handle_properties.h>

#include <vex/core/make_raw_handle.h>
#include <vex/core/allocate_raw_handle.h>
#include <vex/core/any_allocator.h>
#include <vex/core/make_any_allocator.h>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace tests {
    namespace core {

        TEST_CLASS(allocate_raw_handle)
        {
            BEGIN_TEST_CLASS_ATTRIBUTE()
                TEST_CLASS_ATTRIBUTE(L"Module", L"tests.core.allocate_raw_handle")
            END_TEST_CLASS_ATTRIBUTE();
            
            VEX_TESTS_TRACKED_MEM_CHECK();
        public:
            TEST_METHOD_INITIALIZE(set_up)
            {
                VEX_TESTS_TRACKED_MEM_CHECK_START();
            }

            TEST_METHOD_CLEANUP(tear_down)
            {
                VEX_TESTS_TRACKED_MEM_CHECK_FINISH();
            }

            vex::core::contract::memory_resource* get_memory_resource() const
            {
                typedef vex::core::implementation::cstdlib_memory_resource mem_resource_t;
                typedef vex::handle_from_base<mem_resource_t, vex::core::unmanaged> mem_resource_handle_t;

                static mem_resource_handle_t s_memory_resource;

                return &s_memory_resource;
            }

            // creates user_base_mro on default heap but passes custom cstdlib memory resource
            TEST_METHOD(make_raw_handle_for_mro_delivers_valid_handle)
            {
                if (auto t_ptr = vex::core::make_raw_handle<user_base_mro>(this->get_memory_resource())) {
                    Assert::IsTrue(this->get_memory_resource() == t_ptr->get_memory_resource());

                    if (auto t_clone_ptr = vex::as_intrusive_from_out(t_ptr->clone())) {
                        if (auto t_clone_ptr_mro = boost::dynamic_pointer_cast<user_base_mro>(t_clone_ptr)) {
                            Assert::IsTrue(this->get_memory_resource() == t_clone_ptr_mro->get_memory_resource());
                        }
                    }

                    t_ptr->release();
                }
            }

            TEST_METHOD(allocate_raw_handle_delivers_a_valid_handle)
            {
                if (auto t_handle = vex::core::allocate_raw_handle<user_base>(this->get_memory_resource())) {
                    t_handle->release();
                }
            }

            TEST_METHOD(allocate_raw_handle_with_allocator_delivers_a_valid_handle)
            {
                typedef vex::handle_from_base<user_base> user_base_handle_t;
                if (auto t_allocator = vex::make_any_allocator<user_base_handle_t>(this->get_memory_resource())) {
                    if (auto t_handle = vex::core::allocate_raw_handle<user_base>(t_allocator)) {
                        t_handle->release();
                    }
                }
            }

            TEST_METHOD(allocate_raw_handle_for_mro_delivers_a_valid_handle)
            {
                if (auto t_handle = vex::core::allocate_raw_handle<user_base_mro>(this->get_memory_resource())) {
                    t_handle->release();
                }
            }
        };
    }
}